﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Crm.Sdk;
using System.ComponentModel;

namespace Streamsol.Crm.XrmDevelopmentToolkit
{
    /// <summary>
    /// This class encapsulates information of an entity relationship; ID, Type and Display Name of the entity.
    /// </summary>
    [TypeConverter(typeof(XrmReferenceTypeConverter))]
    public class XrmReference
    {
        public Guid Id { get; set; }
        public string EntityTypeName { get; set; }
        public string DisplayName { get; private set; }

        public XrmReference()
        { }

        public XrmReference(Guid id, string entityType, string displayName)
        {
            this.Id = id;
            this.EntityTypeName = entityType;
            this.DisplayName = displayName;
        }

        public XrmReference(Guid id, int crmTypeCode, string displayName) :
            this(id, GetTypeName(crmTypeCode), displayName) { }

        public static string GetTypeName(int crmTypeCode)
        {
            return crmTypeCode < 10000 ? EntityTypeCode.GetTypeName(crmTypeCode) : null;
        }

        public static bool IsNullOrEmpty(XrmReference obj)
        {
            if (obj == null)
                return true;
            else return obj.Id == Guid.Empty;
        }

        public override string ToString()
        {
            return this.DisplayName;
        }

        public static implicit operator Guid(XrmReference obj)
        {
            return obj.Id;
        }

        public static implicit operator Customer(XrmReference obj)
        {
            return new Customer(obj.EntityTypeName, obj.Id);
        }

        public static implicit operator Lookup(XrmReference obj)
        {
            return new Lookup(obj.EntityTypeName, obj.Id);
        }

        public static implicit operator XrmReference(Guid obj)
        {
            return new XrmReference(obj, null, null);
        }
    }

    public class XrmReferenceTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(Guid) || sourceType == typeof(Customer) || sourceType == typeof(Lookup))
                return true;

            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(Guid) || destinationType == typeof(Customer) || destinationType == typeof(Lookup))
                return true;

            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is Guid)
                return new XrmReference((Guid)value, "", "");

            Customer c = value as Customer;
            if (c != null)
            {
                return new XrmReference(c.Value, c.type, c.name);
            }

            Lookup l = value as Lookup;
            if (l != null)
            {
                return new XrmReference(l.Value, l.type, l.name);
            }

            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(Guid))
                return ((XrmReference)value).Id;
            if (destinationType == typeof(Customer))
            {
                XrmReference xrmRef = (XrmReference)value;
                return new Customer(xrmRef.EntityTypeName, xrmRef.Id);
            }
            if (destinationType == typeof(Lookup))
            {
                XrmReference xrmRef = (XrmReference)value;
                return new Lookup(xrmRef.EntityTypeName, xrmRef.Id);
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }
}
